#include "sheduler.h"

namespace sylar{
    static thread_local Sheduler* nowsheduler;
    void Sheduler::setthis(){
        nowsheduler = this;
    }
    Sheduler* Sheduler::getthis(){
        return nowsheduler;
    }
    Sheduler::Sheduler(ssize_t threads ,bool use_caller ,std::string name)
        :_usecaller(use_caller),_name(name)
    {
        setthis();
        Thread::setnowname(name);
        if(use_caller){ //当前线程作为工作线程，那么我们需要给其创建一个主协程来进行调度
            threads--;
            Fiber::getthis(); //创建主协程
            _shedulerfiber.reset(new Fiber(std::bind(&Sheduler::run,this),0,false));
            Fiber::setshedulerfiber(_shedulerfiber.get()); //设置调度协程
            _rootthreadid = Thread::getnowtid();
            _threadsId.push_back(_rootthreadid);

        }
        _threadscount = threads;
        logmessage(NORMAL,"Sheduler::Sheduler succuss");
    }
    void Sheduler::start(){
        std::unique_lock<std::mutex> lock(_mtx);
        //创建和启动线程，每个线程都执行run方法
        _threads.resize(_threadscount);
        for(int i = 0 ; i < _threadscount ; i++){
            _threads[i].reset(new Thread(_name+'-'+std::to_string(i),std::bind(&Sheduler::run,this)));
            _threadsId.push_back(_threads[i]->getpid());
        }
        logmessage(NORMAL,"sheduler start succuss");
    }
    
    //线程需要执行的函数
    void Sheduler::run(){
        logmessage(DEBUG,"Sheduler::run begin threadid:%d",Thread::getnowtid());
        int thread_id = Thread::getnowtid();//获取当前线程的id
        setthis();
        if(thread_id != _rootthreadid){ //非主线程的话，就调用getthis
            Fiber::getthis(); //分配线程的主协程或者调度协程
        }
        //创建空闲协程
        std::shared_ptr<Fiber> idleFiber(std::make_shared<Fiber>(std::bind(&Sheduler::idle,this),0,true));
        ShedulerTask task;
        while(true){
            task.reset();
            bool tickle_me = false; //当前线程遇到了一个指定了其他线程执行的任务，需要唤醒对应线程来处理该任务，避免任务被遗漏。
            {
                std::lock_guard<std::mutex> lock(_mtx);
                auto it = _Tasks.begin();
                while(it != _Tasks.end()){
                    if((it)->_thread != -1 && (it)->_thread != thread_id){
                        it++;
                        tickle_me = true;
                        continue;;
                    }
                    task = *it ; //取任务
                    _Tasks.erase(it); //从任务队列中删除
                    _activethreadscount++; //该线程就要继续处理
                    break;
                }
                tickle_me = tickle_me || (it != _Tasks.end());
            }
            if(tickle_me) tickle(); //唤醒其他线程
            
            //进行处理task任务逻辑
            if(task._fiber){
                std::lock_guard<std::mutex> lock(task._fiber->_mtx);
                if(task._fiber->getstate() != task._fiber->TERM){
                    task._fiber->resume();// 恢复协程运行
                }
                _activethreadscount--;
                task.reset();
            }else if(task._func){
                //先将函数包装成fiber
                std::shared_ptr<Fiber> func_fiber = std::make_shared<Fiber>(task._func,0,true);
                {
                    std::lock_guard<std::mutex> lock(func_fiber->_mtx);
                    func_fiber->resume();
                }
                _activethreadscount--;
                task.reset();
            }else{
                //调用空闲协程空闲下去
                if(idleFiber->getstate() == Fiber::TERM){
                    logmessage(NORMAL,"Sheduler::run end in threadid:%d",thread_id);
                    break;
                }
                _idlethreadscount++;
                idleFiber->resume();
                _idlethreadscount--;//当从这儿恢复后就--
            }
        }
        
    }
    bool Sheduler::can_stop(){
        std::lock_guard<std::mutex> lock(_mtx);
        //是否收到stop 
        return _isstopping&&_Tasks.empty()&&_activethreadscount==0;
    }

    void Sheduler::stop(){
        logmessage(NORMAL,"Sheduler stop begin in threadid %d",Thread::getnowtid());
        if(can_stop()){
            //已经收到暂停请求
            return;
        }
        _isstopping = true;
        //唤醒所有线程
        for(int i = 0 ; i < _threadscount;i++){
            tickle();
        }
        if(_shedulerfiber){
            tickle();
        }
        if(_shedulerfiber){
            _shedulerfiber->resume();
            logmessage(NORMAL,"shedulerfiber resume end");
        }
        std::vector<std::shared_ptr<Thread>> shared_thr;
        {
            std::lock_guard<std::mutex> lock(_mtx);
            shared_thr.swap(_threads);
        }
        for(auto& x: shared_thr){
            x->join();
        }

        logmessage(NORMAL,"sheduler stop end in threadid:%d",Thread::getnowtid());

    }

    void Sheduler::tickle(){
        //TODO
    }

    void Sheduler::idle(){
        while(!can_stop()){
            
            logmessage(NORMAL,"Scheduler::idle(), sleeping in thread: %d",Thread::getnowtid());
            sleep(1);
            Fiber::getthis()->yield();//当前协程主动让出
        }
    }
    Sheduler::~Sheduler(){
        logmessage(NORMAL,"Sheduler::~Sheduler");
    }

}